/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file properties.cpp
 * @author TooOld2Rock'nRoll
 * @see properties.hpp
 */
/*---- Includes ----*/
#include "properties.hpp"

#include "toolbox/debug.h"
#include <glm/fwd.hpp>


/*---- Global Variables ----*/


/*---- Methods Implementation ----*/
/**
 * @brief Adds or subtracts from the objects's current position.
 *
 * @param trans - reference to x,y,z values to move the sprite.
 */
void Position::translate (const glm::vec3 &trans)
{
    _debug (TRACE, "::%s (x=%+.2f, y=%+.2f, z=%.2f)", __FUNCTION__, trans.x, trans.y, trans.z);

    // if (trans == glm::vec3 (0.f))
    //     return; //avoid rebuilding model

    this->_property += trans;
    this->b_dirty_flag = true;

    if (!this->p_ext_reference.expired ())
        *this->p_ext_reference.lock() = this->_property;
}//End translate


//I don't like this, but C++ enums are type strong...........
/** @brief Bitwise operator 'or' overload for a bitmask enum. */
inline constexpr Angle2D::rotate_at operator| (const Angle2D::rotate_at &lhs,
                                                       const Angle2D::rotate_at &rhs)
{
    return (Angle2D::rotate_at)((unsigned)lhs | (unsigned)rhs);
}//end operator|

/** @brief Bitwise operator 'and' overload for a bitmask enum. */
inline constexpr Angle2D::rotate_at operator& (const Angle2D::rotate_at &lhs,
                                                       const Angle2D::rotate_at &rhs)
{
    return (Angle2D::rotate_at)((unsigned)lhs & (unsigned)rhs);
}//end operator&

/** @brief Bitwise assignment operator 'or' overload for a bitmask enum. */
inline Angle2D::rotate_at& operator|= (Angle2D::rotate_at &lhs,
                                               const Angle2D::rotate_at &rhs)
{
    lhs = (lhs | rhs);
    return lhs;
}//end operator|=

/** @brief Bitwise assignment operator 'and' overload for a bitmask enum. */
inline Angle2D::rotate_at& operator&= (Angle2D::rotate_at &lhs,
                                               const Angle2D::rotate_at &rhs)
{
    lhs = (lhs & rhs);
    return lhs;
}//end operator&=


/**
 * @brief Sets a specific reference to rotate/mirror the object at.
 *
 * @param at - (bit mask) the position reference.
 */
void Angle2D::setRotationPoint (Angle2D::rotate_at at)
{
    _debug (TRACE, "::%s (at=%#06X)", __FUNCTION__, at);

    this->b_dirty_flag = true;
    this->v2_rotation_point = glm::vec2 (0.5);

    if ((at & rotate_at::TOP) == rotate_at::TOP)
        this->v2_rotation_point.y = 0.f;
    else if ((at & rotate_at::BOTTOM) == rotate_at::BOTTOM)
        this->v2_rotation_point.y = 1.f;

    if ((at & rotate_at::LEFT) == rotate_at::LEFT)
        this->v2_rotation_point.x = 0.f;
    else if ((at & rotate_at::RIGHT) == rotate_at::RIGHT)
        this->v2_rotation_point.x = 1.f;
}//end setRotationCenter ()


/**
 * @brief Adds or subtracts from the object´s angle around the Z axle.
 *
 * @param r - how many degrees to rotate.
 */
void Angle2D::rotate (float r)
{
    _debug (TRACE, "::%s (x=%+.2f)", __FUNCTION__, r);

    if (r == 0.f)
        return; //avoid rebuilding model

    this->_property += r;
    this->b_dirty_flag = true;

    if (!this->p_ext_reference.expired ())
        *this->p_ext_reference.lock() = this->_property;
}//End rotate ()


/**
 * @brief A scale to be applied independently to the current size.
 *
 * This is probably what you want to keep all your sprites size consistent to each other in different resolutions,
 *    since it won't be overridden by other resize operations.
 *
 * @param s_factor - how much to scale.
 */
void Size::setScaleFactor (float s_factor)
{
    _debug (TRACE, "::%s (s_factor=%.2f)", __FUNCTION__, s_factor);

    if (s_factor == this->f_scale_factor)
        return; //avoid rebuilding model

    this->b_dirty_flag = true; //set size to be recalculated on draw!
    this->f_scale_factor = s_factor;
}//End setScaleFactor ()

